'''
ORDER для менеджеров.
Все кодировки можно читать в словари а потом подставлять.
'''
import sys
import logging                                                                  # запись логов

from datetime import date, timedelta

from modules.connmysql import get_db_mysql
from modules.login import get_user
from modules.modulemenager import ModuleMenager

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtSql import *

# sys.path.append('c:\PyLib')


def field_column(model):
    """ Создание словаря для QSqlQueryModel.
    Ключ - имя поля, значение - номер столбца."""
    D = {}
    for i in range(model.columnCount()):
        D[model.record().fieldName(i)] = i
    return D


class MainForm(QWidget):
    """
    В процессе исполнения кода все виджеты формы создаются как локальные переменные.
    Затем закладываются в контейнеры виждеты. Вся итоговая структура локальных
    сохраняется оператором self.setLayout(vbox). Чтобы иметь доступ к элементам
    класса, используем self там, где необходимо.
    """

    def __init__(self, parent=None):
        super().__init__()
        self.initUI()
    
    def initUI(self):
    
        """ Виджет вкладок. Первая вкладка класс TaskTab (таблица персональных 
        заданий. Вторая вкладка класс OrderTab (таблица общей очереди)."""
        self.tab = QTabWidget()
        self.task_tab = TaskTab()
        self.tab.addTab(self.task_tab, "МОИ ЗАКАЗЫ")
        self.order_tab = OrderTab()
        self.tab.addTab(self.order_tab, "ОБЩАЯ ОЧЕРЕДЬ")

        """ Размещение на виджете через QVBoxLayout."""
        vbox = QVBoxLayout()
        vbox.addWidget(self.tab)
        self.setLayout(vbox)
        
        self.tab.currentChanged.connect(self.tab_changed) 
        self.tab.setCurrentIndex(0)
        self.startTimer(60000)                                                  # 60 секунд
        


    def tab_changed(self, index):
    
        """ Обновление содержимого таблиц при переключениии вкладок."""
        if index == 0:
            self.task_tab.model.setQuery(self.task_tab.model.query().lastQuery())
        if index == 1:
            self.order_tab.model.setQuery(self.order_tab.model.query().lastQuery())

    def timerEvent(self,  event):
    
        """ Обновление содержимого таблиц по таймеру для текущей вкладки."""
        self.tab_changed(self.tab.currentIndex())



class TaskTab(QWidget):
    ''' Вкладка для отображения "своих" заказов во всех состояниях.'''
    def __init__(self, parent=None):
        super().__init__()

        self.setup_ui()
        self.init()


    def setup_ui(self):

        """ КНОПКА """
        btn_module_new = QPushButton(" НОВЫЙ МОДУЛЬ ")
        btn_module_new.clicked.connect(self.new_module)

        """ ТАБЛИЦА. События: двойной клик и контекстное меню. """
        self.view = QTableView()
        self.view.resizeColumnsToContents()
        self.view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.view.doubleClicked.connect(self.double_clik)
        self.view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.view.customContextMenuRequested.connect(self.shortcut_menu)

        hbox = QHBoxLayout()
        hbox.addWidget(btn_module_new)
        hbox.addStretch()

        vbox = QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addWidget(self.view)
        self.setLayout(vbox)


    def init(self):

        global col_num

        """ Показываем выполненные заказы за три рабочих дня """
        dat = date.today()
        if dat.weekday() == 0:                                                  # понедельник
            days = 4
        elif dat.weekday() == 1:                                                # вторник
            days = 5
        else:
            days = 3
        dat = dat - timedelta(days=3)
        dat = dat.strftime('%Y-%m-%d')

        """ МОДЕЛЬ """
        self.model = TaskModel()                                                # создаём для неё модель данных
        sql = (
            "SELECT '' as status, job, num_asu_new, quickly, designer, "
            "data_ready, date_start, date_finish, rec_id, class "
            "FROM store "
            "WHERE ((date_finish IS NULL) OR (date_finish > '{}')) AND (customer = {}) "
            "ORDER BY designer, data_ready".format(dat, user.rec_id))
        self.model.setQuery(sql)
        if self.model.lastError().isValid ():
            logging.critical('TabModel: {}'.format( self.model.lastError().text()))
            quit()
        col_num = field_column(self.model)

        """ ЗАГОЛОВКИ ТАБЛИЦЫ """
        self.model.setHeaderData(col_num["status"], Qt.Horizontal, 'Состояние')
        self.model.setHeaderData(col_num["job"], Qt.Horizontal, 'Задание')
        self.model.setHeaderData(col_num["num_asu_new"], Qt.Horizontal, '№ АСУ')
        self.model.setHeaderData(col_num["quickly"], Qt.Horizontal, 'Важность')
        self.model.setHeaderData(col_num["designer"], Qt.Horizontal, 'Дизайнер')
        self.view.setModel(self.model)

        # for column in range(5, self.model.record().count()):
            # self.view.setColumnHidden(column, True)

    def new_module(self):
        ''' Добавляем новую запись. Номер записи query.lastInsertId().
        Открываем форму ModuleMenager и передаем ей управление, чтобы
        рефрешь был выполнен после закрытия формы.'''
        query = QSqlQuery()
        query.exec("INSERT orders.store (kind, customer) VALUES(0,{});"
            .format(user.rec_id));
        if query.lastError().isValid ():
            logging.critical('Новый модуль: {}'.format( self.model.lastError().text()))
            quit()
        rec_id = query.lastInsertId()
        self.module_new = ModuleMenager(window, rec_id)
        self.module_new.exec_()
        self.model.setQuery(self.model.query().lastQuery())

    def double_clik(self, item):
    
        # РЕДАКТИРОВАТЬ ВЫДЕЛЕННУЮ ЗАПИСЬ
        """ Находим ключевое поле таблицы."""
        row = item.row()
        rec_id = self.model.record(row).value('rec_id')
        """ Сбрасываем флаг готовности задания. Хранимая функция. Описание в БД."""
        query = QSqlQuery()
        query.exec("SELECT reset_ready({});".format(rec_id))
        query.next()
        designer = query.value(0)
        """ Если заказ уже взял дизайнер, выводим сообщение. """
        if designer:
            report = QMessageBox()
            report.setIcon(QMessageBox.Warning) # иконка
            report.setWindowTitle("ЗАДАНИЕ УЖЕ ВЫПОЛНЯЕТСЯ")
            report.setText("Дизайнер {} должен отменить выполнение задания. "
                "После этого вы сможете его отредактировать.".format(designer))
            report.setWindowIcon(QIcon("pict\\order.ico"))
            report.exec_()
            return

        """ Редактировать запись в отдельной форме. Передать управление в форму.
        После закрытия формы сделать рефрешь таблицы."""
        module = ModuleMenager(main_form, rec_id)
        module.exec_()
        self.model.setQuery(self.model.query().lastQuery())

    def shortcut_menu(self, pos):
    
        #
        """ КОНТЕКСТНОЕ МЕНЮ. Создаём и запускаем"""
        menu = QMenu(self)
        menu.addAction("Создать копию", self.double_task)
        menu.addAction("Найти заказ и создать копию", self.find_task)
        menu.addAction("Удалить забытый заказ", self.delete_task)
        menu.exec_(QCursor.pos())

    def double_task(self):
        # ДУБЛИРОВАТЬ ЗАКАЗ
        """ Номер строки (= номеру записи в модели) берём из таблицы. По номеру 
        записи находим значение ключевого поля."""
        row_tab = self.view.currentIndex().row()                              
        rec_id = self.model.record(row_tab).value('rec_id')
        self.double_record(rec_id)

    def find_task(self):
        # НАЙТИ И СДУБЛИРОВАТЬ ЗАКАЗ
        """ Запрашиваем номер АСУ для поиска."""
        number, ok = QInputDialog.getText(self, "ПОИСК ЗАКАЗА",
                "Введите № АСУ для поиска:",QLineEdit.Normal, "");
        if not ok or not number:
            return
        """ Ищем:  номер АСУ, готовый, самый свежий, ОДИН! """
        print(number)
        query = QSqlQuery()
        query.exec("SELECT rec_id FROM store "
            "WHERE (date_finish IS NOT NULL) AND (num_asu_new = {}) "
            "ORDER BY date_order DESC LIMIT 1".format(number))           
        if not query.size():
            QMessageBox.warning(self,"НЕ НАЙДЕНО",
                "Такого номера АСУ в базе заказов нет.")
            return
        query.next()
        rec_id = int(query.value(0))
        self.double_record(rec_id)
            
    def double_record(self, rec_id):
        """ Дублирует заказ функция БД. Ей передаётся ключевое поле для 
        дублирования и код менеджера - кому приписать новую запись. Функция 
        возвращает ключевое поле новой записи."""
        sql = "SELECT double_task({},{})".format(rec_id, user.rec_id)
        query.exec(sql)
        if query.lastError().isValid ():
            logging.critical('double_task: {}'.format( query.lastError().text()))
            quit()
        query.next()
        rec_id = int(query.value(0))
        """ Обновляем таблицу, чтобы новая запись появилась в модели. Ищем,
        начиная с элемента: первая строка записи, колонка ключевого поля. Роль - 
        информация. Искать код """
        self.model.setQuery(self.model.query().lastQuery())
        indexList = self.model.match(self.model.index(0, col_num["rec_id"]), Qt.DisplayRole, rec_id)
        index = indexList[0].row()
        self.view.selectRow(index)
    

    def delete_task(self):
        # УДАЛИТЬ ВЫДЕЛЕННУЮ ЗАПИСЬ

        """ Берём ключевое поле таблицы."""
        row = self.view.currentIndex().row()
        rec_id = self.model.record(row).value('rec_id')

        sql = ("DELETE FROM store "
            "WHERE (designer IS NULL) AND (rec_id = {});".format(rec_id))
        query = QSqlQuery()
        query.exec(sql)
        if query.numRowsAffected() == 0:
            QMessageBox.critical(self,"УДАЛЕНИЕ НЕВОЗМОЖНО",
                "Уже началось выполнение задания. Необходимо связаться с дизайнером.")
        self.model.setQuery(self.model.query().lastQuery())


class TaskModel(QSqlQueryModel):

    def __init__(self, parent=None):
        super().__init__()                                                      # запускаем init родительского класса

        self.green = QColor.fromRgb(193, 255, 193)
        self.red = QColor.fromRgb(255, 215, 215)


    def data(self, item, role):
        """ Передается элемент (QModelIndex) который прорисовывается и роль. """

        value = super(TaskModel, self).data(item, role)                         
        row = item.row()

        # ОТОБРАЖАЕМАЯ ИНФОРМАЦИЯ
        if role == Qt.DisplayRole:

            """ СТАТУС."""
            if item.column() == self.record().indexOf("status"):                # статус заказа
                if self.record(row).value('date_finish'):
                    value = 'ГОТОВ'
                if not self.record(row).value('data_ready'):
                    value = 'ЗАБЫТЫЙ'
                if self.record(row).value('data_ready') and not self.record(row).value('date_start'):
                    value = 'В ОЧЕРЕДИ'
                if self.record(row).value('date_start') and not self.record(row).value('date_finish'):
                    value = 'ВЫПОЛНЯЕТСЯ'

            """ ТИП."""
            if item.column() == self.record().indexOf("job"):                   # тип заказа
                if value == 0:
                    value = 'модуль'
            """ ВАЖНОСТЬ."""
            if item.column() == self.record().indexOf("quickly"):               # важность
                if value == 1:
                    value = 'СРОЧНО'
                else:
                    value = ''
            """ МЕНЕДЖЕР."""
            if item.column() == self.record().indexOf("customer"):              
                if value in user_dict:
                    value = user_dict[value]
                else:
                    value = ''
            """ ДИЗАЙНЕР."""
            if item.column() == self.record().indexOf("designer"):              
                if value in user_dict:
                    value = user_dict[value]
                else:
                    value = ''

        # ВЫРАВНИВАНИЕ
        if role == Qt.TextAlignmentRole:
            if item.column() == 2:
                return int(Qt.AlignRight | Qt.AlignVCenter)
            else:
                return int(Qt.AlignCenter | Qt.AlignVCenter)

        # ЦВЕТ ТЕКСТА
        if role == Qt.TextColorRole:
            if item.column() == self.record().indexOf("status"):
                if self.record(row).value('date_finish'):
                    return QColor(Qt.blue)
                if (self.record(row).value('date_start')) and (not self.record(row).value('date_finish')):
                    return QColor(Qt.green)
            # if item.column() == self.record().indexOf("status"):
                # return QColor(Qt.blue)
            if item.column() == self.record().indexOf("quickly"):
                return QColor(Qt.red)

        # ЦВЕТ ФОНА
        # if role == Qt.BackgroundRole:
            # status = ''
            # if self.record(row).value('data_ready'):
                # status = 'Забытый'
            # row = index.row()
            # if (self.record(row).value('date_start') and
                # not self.record(row).value('date_finish')):
                # return QBrush(self.green)
            # if (self.record(row).value('data_ready') and
                # not self.record(row).value('date_start')):
                # return QBrush(self.red)

        return value


class OrderTab (QWidget):

    def __init__(self, parent=None):
        super().__init__()                                                      # запускаем init родительского класса

        self.setup_ui()
        self.init()

    def setup_ui(self):

        self.view = QTableView()
        self.view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

        vbox = QVBoxLayout()
        vbox.addWidget(self.view)
        self.setLayout(vbox)

    def init(self):

        self.model = OrderModel()                                               # создаём для неё модель данных
        sql = (
            "SELECT job, date_order, customer, num_asu_new, designer, "
            "TIMEDIFF(NOW(), date_start) AS time_work, quickly "
            "FROM store "
            "WHERE (date_finish IS NULL) AND (data_ready = 1) "
            "ORDER BY quickly DESC, date_order ASC"
            )
        self.model.setQuery(sql)
        if self.model.lastError().isValid ():
            logging.critical('TabModel: {}'.format( self.model.lastError().text()))
            quit()
        col_num = field_column(self.model)

        """ ЗАГОЛОВКИ ТАБЛИЦЫ тип менеджер асу дизайнер время срочно"""
        self.model.setHeaderData(col_num["job"], Qt.Horizontal, 'Задание')
        self.model.setHeaderData(col_num["date_order"], Qt.Horizontal, 'В очереди с')
        self.model.setHeaderData(col_num["customer"], Qt.Horizontal, 'Менеджер')
        self.model.setHeaderData(col_num["num_asu_new"], Qt.Horizontal, '№ АСУ')
        self.model.setHeaderData(col_num["designer"], Qt.Horizontal, 'Дизайнер')
        self.model.setHeaderData(col_num["time_work"], Qt.Horizontal, 'Секундомер')
        self.model.setHeaderData(col_num["quickly"], Qt.Horizontal, 'Важность')
        self.view.setModel(self.model)


class OrderModel(QSqlQueryModel):

    def __init__(self, parent=None):
        super().__init__()                                                      # запускаем init родительского класса

        self.green = QColor.fromRgb(193, 255, 193)
        self.red = QColor.fromRgb(255, 215, 215)


    def data(self, item, role):
        """ Передается элемент (QModelIndex) который прорисовывается и роль. """

        value = super(OrderModel, self).data(item, role)                        # Returns the value for the specified item and role.

        # ОТОБРАЖАЕМАЯ ИНФОРМАЦИЯ
        if role == Qt.DisplayRole:

            row = item.row()
            """ СТАТУС."""
            if item.column() == self.record().indexOf("status"):                # статус заказа
                if not self.record(row).value('data_ready'):
                    value = 'ЗАБЫТЫЙ'
                if self.record(row).value('data_ready') and not self.record(row).value('date_start'):
                    value = 'В ОЧЕРЕДИ'
                if self.record(row).value('date_start') and not self.record(row).value('date_finish'):
                    value = 'ВЫПОЛНЯЕТСЯ'
                if self.record(row).value('date_finish'):
                    value = 'ГОТОВ'

            """ ТИП."""
            if item.column() == self.record().indexOf("job"):                   # тип заказа
                if value == 0:
                    value = 'модуль'
            """ ВАЖНОСТЬ."""
            if item.column() == self.record().indexOf("quickly"):               # важность
                if value == 1:
                    value = 'СРОЧНО'
                else:
                    value = ''
            """ МЕНЕДЖЕР."""
            if item.column() == self.record().indexOf("customer"):              
                if value in user_dict:
                    value = user_dict[value]
                else:
                    value = ''
            """ ДИЗАЙНЕР."""
            if item.column() == self.record().indexOf("designer"):              
                if value in user_dict:
                    value = user_dict[value]
                else:
                    value = ''

        # ВЫРАВНИВАНИЕ
        if role == Qt.TextAlignmentRole:
            if item.column() == 2:
                return int(Qt.AlignRight | Qt.AlignVCenter)
            else:
                return int(Qt.AlignCenter | Qt.AlignVCenter)

        # ЦВЕТ ТЕКСТА
        if role == Qt.TextColorRole:
            if item.column() == self.record().indexOf("status"):
                return QColor(Qt.blue)
            if item.column() == self.record().indexOf("quickly"):
                return QColor(Qt.red)

        # ЦВЕТ ФОНА
        # if role == Qt.BackgroundRole:
            # status = ''
            # if self.record(row).value('data_ready'):
                # status = 'Забытый'
            # row = index.row()
            # if (self.record(row).value('date_start') and
                # not self.record(row).value('date_finish')):
                # return QBrush(self.green)
            # if (self.record(row).value('data_ready') and
                # not self.record(row).value('date_start')):
                # return QBrush(self.red)

        return value

        
        
def main():

    global user # ссылка на инфу по юзеру
    global db # ссылка на БД
    global user_dict # 
    global main_form
    
    app = QApplication(sys.argv)
    
    logging.basicConfig(filename='menager.log',level=logging.DEBUG,
        format = u'%(filename)s[LINE:%(lineno)d]# %(levelname)-8s %(message)s')
        
    """ Соединение с БД."""
    db = get_db_mysql("order.ini")
    if not db:
        print("нет соединения")
        quit()
    """ Авторизация пользователя."""
    user = get_user("order.ini")
    if not user:
        quit()

    """ Словарь пользователей. Ключ - код, содержимое фамилия. """
    query = QSqlQuery(db)
    query.exec("SELECT rec_id, surname FROM users;")           
    user_dict = {}
    while query.next():
        user_dict[query.value(0)] = query.value(1)

    """установим желтый цвет в качестве фона во всех объектах QLine Edit приложения. Этого можно достичь следующим образом:
    qApp->setStyleSheet("QLineEdit { background-color: yellow }");"""
    # app.setStyleSheet("QWidget { font-size: 14px }")
    """ Создаем материнское окно."""
    main_form = MainForm()                                                        
    main_form.setWindowTitle("ОРДЕР")
    main_form.setWindowIcon(QIcon("pict\\order.ico"))
    main_form.resize(700, 600)
    main_form.show()                                                               
    sys.exit(app.exec_())                                                      


if __name__ == '__main__':                                               
    main()
